package com.blb.day20231106springsecurity.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * SpringSecurity整合MVC配置，继承WebSecurityConfigurerAdapter
 * Adapter适配器设计模式，实现接口必须实现接口中所有方法
 * Adapter给接口方法默认实现，继承Adapter后只需要实现特定方法
 */
//启动注解配置授权访问
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //提供密码编码器给容器
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    private UserDetailsService userDetailsService;

    //配置验证的账号密码
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        //在内存中实现验证
//        auth.inMemoryAuthentication()
//                .withUser("lisi")
//                .password(bCryptPasswordEncoder.encode("123"))
////                .roles("ADMIN") //用户 --> 角色 --> 权限
//                .authorities("add-user","ROLE_ADMIN")
//                .and()
//                .withUser("zhangsan")
//                .password(bCryptPasswordEncoder.encode("123"))
//                .roles("GUEST");
        //配置自定义的登录逻辑
        auth.userDetailsService(userDetailsService);
    }

    @Autowired
    private DataSource dataSource;

    @Autowired
    private PersistentTokenRepository persistentTokenRepository;

    //配置访问授权
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //配置资源的授权访问
        http.authorizeRequests().antMatchers(
                "/**/*.css","/**/*.js","/**/*.jpg",
                "/login.html","/login","logout").permitAll() //上面地址放行
                .antMatchers("/admin.html").hasRole("管理员") //设置资源必须有某个角色才能访问
                .antMatchers("/guest.html").hasAnyRole("销售主管","仓管主管")
                .antMatchers("/add-user.html").hasAuthority("生产入库")
                .anyRequest().authenticated()               //其它资源需要登录验证
                .and()
                //登录页面,处理登录的url和登录成功跳转页面的配置
                .formLogin().loginPage("/login.html").loginProcessingUrl("/login").successForwardUrl("/index.html")
                .and()
                //注销的url和注销后跳转页面的配置
                .logout().logoutUrl("/logout").logoutSuccessUrl("/login.html")
                //记住我配置
                .and()
                .rememberMe()
                .rememberMeParameter("rememberMe")
                .tokenRepository(persistentTokenRepository) //数据源
                .tokenValiditySeconds(7 * 24 * 3600); //时间 秒
    }

    /**
     * 配置记住我的数据源
     * @return
     */
    @Bean
    public PersistentTokenRepository persistentTokenRepository(){
        //使用jdbc实现记住我
        JdbcTokenRepositoryImpl repository = new JdbcTokenRepositoryImpl();
        //配置数据源
        repository.setDataSource(dataSource);
        //第一次启动时创建表，后面不能创建
//        repository.setCreateTableOnStartup(true);
        return repository;
    }
}
